
<html>

<body>


    <div id="app">

    </div>
</body>
<script>

    function h(tag, props, children) {
        return {
            tag, props, children
        }
    }
    function patch(n1, n2) {
        console.log(n1,n2)
        let el =n2.el =  n1.el
        let parent = n2.parent = n1.parent
        if (n1.tag != n2.tag) {
            if(parent.contains(el)){

                parent.removeChild(el)
            }
            mount(n2,parent)
            // el = n1.el = n2.el
        }
        else {
            if (typeof n1.children == "string") {
                if (typeof n2.children == "string") {
                    // console.log(el,n1,n2)
                    if(n1.children != n2.children){
                        el.textContent = n2.children
                    }

                }
                else {
                    el.innerHtml=''
                    n2.children.forEach(child=>{
                        mount(child,el)
                    })
                }

            }
            else {
                if (typeof n2.children == "string") {
                    el.textContent = n2.children
                }
                else {
                    let n1len = n1.children?.length ||0
                    let n2len = n2.children?.length ||0
                    const minlen = Math.min(n1len, n2len)
                    for (let i = 0; i < minlen; i++) {
                        patch(n1.children[i],n2.children[i])
                    }
                    if(n1len>=n2len){
                        n1.children.slice(minlen).forEach(child=>{
                            el.removeChild(child.el)
                        })
                    }
                    else{
                        n2.children.slice(minlen).forEach(child=>{
                            mount(child,el)
                        })
                    }
                }
            }
        }
    }

    function mount(vnode, container) {
        let el = document.createElement(vnode.tag)
        if (vnode.props) {
            for (let i in vnode.props) {
                if(i.startsWith('on')){
                    el.addEventListener(i.substring(2),vnode.props[i])
                }
                else{

                    el.setAttribute(i, vnode.props[i])
                }
            }
        }
        if (vnode.children) {

            if (typeof vnode.children === "string") {
                el.textContent = vnode.children
            }
            else {
                for (let i = 0; i < vnode.children.length; i++) {
                    mount(vnode.children[i], el)
                }
            }
        }
        container.appendChild(el)
        vnode.el = el
        vnode.parent = container
    }

    const targetMap = new Map()
    const targetSet = new Set()
    function reactive(obj) {
        if (!targetMap[obj]) {

            targetMap[obj] = new Proxy(obj, {
                get(target, name, receiver) {
                    console.log(name)
                    targetSet.add(target)
                    return target[name]
                },
                set(target, name, value, receiver) {
                    console.log(22)
                    target[name] = value
                    if(targetSet.has(target)){
                        notify()
                    }
                    
                }
            })
        }
        return targetMap[obj]
    }


    // const vnode1 = h('div', {
    //         id: 'hy'
    //     }, [h('span', null, 'hello'), h('span', {
    //         'class': 's2'
    //     }, 'hello'), h('span', {
    //         'class': 's3'
    //     }, [h('div', {
    //         // 'onClick':()=>{

    //         // }
    //     }, 'hello1')])])
    // const vnode2 = h('div', {
    //         id: 'hy'
    //     }, [h('span', null, 'hello'), h('span', {
    //         'class': 's2'
    //     }, 'hello'), h('span', {
    //         'class': 's3'
    //     }, [h('div', {
    //         // 'onClick':()=>{

    //         // }
    //     }, 'hello2')])])
    // patch(vnode1,vnode2)
    const App ={
        data:reactive({
            id:0,
            name:'ss',
        }),
        render(){
            // console.log(App.data.id)
            let arr=[]
            for(let i =0;i<App.data.id;i++){
                arr.push(h('div',null,App.data.id+'_'+i))
            }
            arr.push(h('input',{'value':App.data.name,'oninput':(e)=>{
                App.data.name = e.target.value
            }},[])
            )
            arr.push(h('span',null,App.data.name))
            console.log(arr)
            return   h('div',null,[...arr,h('button',{
                'onclick':()=>{
                    App.data.id++
                },
            },'加加')])
        }
    }
    let notifyFun 
    function watchEffect(fn){
        notifyFun = fn
        notifyFun()
    }
    function notify(){
        notifyFun && notifyFun()
    }
    function mountApp(component,container){
        let preNode = component.render()
        let isMounted = false
        watchEffect(()=>{
            
            if(isMounted){
                newNode = component.render()
                patch(preNode,newNode)
                preNode = newNode
            }
            else{
    
                mount(preNode,container)
                isMounted=true
            }
        })
    }
    mountApp(App,document.getElementById('app'))
</script>

</html>